package com.techblor.docker.mojo;

import com.techblor.docker.bean.DockerfileCommand;
import com.techblor.docker.config.DirectoryConfig;
import com.techblor.docker.config.HealthcheckConfig;
import com.techblor.docker.config.ImageConfig;
import com.techblor.docker.util.JoinerUtil;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Mojo(name = "build", threadSafe = true)
public class BuildMojo extends AbstractDockerMojo {

    /**
     * 重入锁: 防止重复执行构建命令
     */
    private static final Lock LOCK = new ReentrantLock();

    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            LOCK.lock();
            super.execute();
        } finally {
            LOCK.unlock();
        }
    }

    @Override
    public List<String> buildCommand() {
        try {
            buildDockerfile();


        } catch (IOException e) {
            e.printStackTrace();
            getLog().error(e);
        }

        return new ArrayList<>();
    }

    @Override
    public void executeCommand(List<String> command) {
        System.out.println(command);
    }

    private void buildDockerfile() throws IOException {
        String dockerfile = directory.getDockerfile();
        String targetPath = directory.getTargetPath();
        String projectPath = directory.getProjectPath();
        String projectFile = directory.getProjectFile();

        if (dockerfile != null && !dockerfile.trim().equals("")) {
            // 已定义dockerfile

        } else {
            // 未定义dockerfile, 生成dockerfile
            DockerfileCommand dockerfileCommand = buildDockerfileCommand(image, directory);
            String buildDirectory = getBuildDirectory(projectPath);

            getLog().debug("Writing Dockerfile:" + System.lineSeparator() +
                    JoinerUtil.join(dockerfileCommand.getCommand(), System.lineSeparator()));

            Files.createDirectories(Paths.get(buildDirectory));
            Files.write(Paths.get(buildDirectory, "Dockerfile"), dockerfileCommand.getCommand(), StandardCharsets.UTF_8);

            /*FileWriter fileWriter = null;
            PrintWriter printWriter = null;
            try {

                File file = new File(buildDirectory, "Dockerfile");
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }

                file.createNewFile();
                fileWriter = new FileWriter(file);
                printWriter = new PrintWriter(fileWriter);
                List<String> command = dockerfileCommand.getCommand();
                for (String value : command) {
                    printWriter.println(value);
                }

                printWriter.flush();
                fileWriter.flush();
            } catch (IOException e) {
                getLog().error(e);
            } finally {
                printWriter.close();
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    getLog().error(e);
                }
            }*/
        }
    }

    private String getBuildDirectory(String projectPath) {
        return Paths.get(projectPath, "docker").toString();
    }

    private DockerfileCommand buildDockerfileCommand(ImageConfig image, DirectoryConfig directory) {
        DockerfileCommand.DockerfileCommandBuilder builder = DockerfileCommand.builder();

        if (image.getFrom() != null) {
            builder.addCommand("FROM", image.getFrom());
        }

        if (image.getRun() != null && image.getRun().size() > 0) {
            List<String> run = image.getRun();
            for (String item : run) {
                builder.addCommand("RUN", item);
            }
        }

        if (image.getCopy() != null && image.getCopy().size() > 0) {
            List<String> copy = image.getCopy();
            for (String item : copy) {
                builder.addCommand("COPY", item);
            }
        }

        if (image.getAdd() != null && image.getAdd().size() > 0) {
            List<String> add = image.getAdd();
            for (String item : add) {
                builder.addCommand("ADD", item);
            }
        } else {
            if(directory.getDockerfile() != null && directory.getProjectPath() != null && directory.getProjectFile() != null) {
                builder.addCommand("ADD", String.format("%s %s", directory.getProjectFile(), directory.getTargetPath()));
            }

        }

        if (image.getCmd() != null && image.getCmd().size() > 0) {
            List<String> cmd = image.getCmd();
            for (String item : cmd) {
                builder.addCommand("CMD", item);
            }
        }

        if (image.getEntryPoint() != null) {
            builder.addCommand("ENTRYPOINT", image.getEntryPoint());
        }

        if (image.getEnv() != null) {
            Map<String, String> env = image.getEnv();
            Set<String> keySet = env.keySet();
            for (String key : keySet) {
                String value = String.format("%s=%s", key, env.get(key));
                builder.addCommand("ENV", value);
            }
        }

        if (image.getArg() != null) {
            Map<String, String> arg = image.getArg();
            Set<String> keySet = arg.keySet();
            for (String key : keySet) {
                String value = String.format("%s=%s", key, arg.get(key));
                builder.addCommand("ARG", value);
            }
        }

        if (image.getVolume() != null && image.getVolume().size() > 0) {
            List<String> volume = image.getVolume();
            for (String item : volume) {
                builder.addCommand("VOLUME", item);
            }
        }

        if (image.getExpose() != null && image.getExpose().size() > 0) {
            List<String> expose = image.getExpose();
            for (String item : expose) {
                builder.addCommand("EXPOSE", item);
            }
        }

        if (image.getWorkdir() != null) {
            builder.addCommand("WORKDIR", image.getWorkdir());
        }

        if (image.getUser() != null) {
            builder.addCommand("USER", image.getUser());
        }

        if (image.getHealthcheck() != null) {
            StringBuilder sb = new StringBuilder();
            HealthcheckConfig healthcheck = image.getHealthcheck();
            if (healthcheck.getInterval() != null) {
                sb.append(String.format("--interval=%s ", healthcheck.getInterval()));
            }

            if (healthcheck.getTimeout() != null) {
                sb.append(String.format("--timeout=%s ", healthcheck.getTimeout()));
            }

            if (healthcheck.getRetries() != null) {
                sb.append(String.format("--retries=%d ", healthcheck.getRetries()));
            }

            if (healthcheck.getCmd() != null) {
                sb.append("CMD ").append(healthcheck.getCmd());
            }

            builder.addCommand("HEALTHCHECK", sb.toString());
        }

        if (image.getLabel() != null && image.getLabel().size() > 0) {
            List<String> label = image.getLabel();
            for (String item : label) {
                builder.addCommand("LABEL", item);
            }
        }

        return builder.build();
    }

    private void createDockerfile() {

    }
}
